`timescale 1ns/1ns

// 流水线8bit加法器

module pipeline_add8 (
    input   wire            clk     ,
    input   wire            rstn    ,
    input   wire    [7:0]   in1     ,
    input   wire    [7:0]   in2     ,
    input   wire            cin     ,
    output  wire    [7:0]   sum     ,
    output  wire            cout     
);

// 输入数据寄存
reg [7:0] in1_pipeline0, in2_pipeline0;
reg cin_pipeline0;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline0 <= 0;
        in2_pipeline0 <= 0;
        cin_pipeline0 <= 0;
    end
    else begin 
        in1_pipeline0 <= in1;
        in2_pipeline0 <= in2;
        cin_pipeline0 <= cin;
    end
end

// 第一级计算：bit0 + bit1 
wire [2:0] add1;
assign add1 = in1_pipeline0[1:0] + in2_pipeline0[1:0] + cin_pipeline0;
    
// 第一级数据寄存
reg [7:2] in1_pipeline1, in2_pipeline1;
reg [1:0] sum_pipeline1;
reg       co2_pipeline1;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline1[7:2] <= 0;
        in2_pipeline1[7:2] <= 0;
        sum_pipeline1[1:0] <= 0;
        co2_pipeline1      <= 0;
    end
    else begin 
        in1_pipeline1[7:2] <= in1_pipeline0[7:2];
        in2_pipeline1[7:2] <= in2_pipeline0[7:2];
        sum_pipeline1[1:0] <= add1[1:0];
        co2_pipeline1      <= add1[2];
    end
end

// 第二级计算：bit2 + bit3
wire [4:2] add2 = in1_pipeline1[3:2] + in2_pipeline1[3:2] + co2_pipeline1;

// 第二级数据寄存
reg [7:4] in1_pipeline2, in2_pipeline2;
reg [3:0] sum_pipeline2;
reg       co4_pipeline2;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline2[7:4] <= 0;
        in2_pipeline2[7:4] <= 0;
        sum_pipeline2[3:0] <= 0;
        co4_pipeline2      <= 0;
    end
    else begin 
        in1_pipeline2[7:4] <= in1_pipeline1[7:4];
        in2_pipeline2[7:4] <= in2_pipeline1[7:4];
        sum_pipeline2[3:0] <= {add2[3:2], sum_pipeline1[1:0]};
        co4_pipeline2      <=  add2[4];
    end
end

// 第三级计算：bit4 + bit5
wire [6:4] add3 = in1_pipeline2[5:4] + in2_pipeline2[5:4] + co4_pipeline2;

// 第三级数据寄存
reg [7:6] in1_pipeline3, in2_pipeline3;
reg [5:0] sum_pipeline3;
reg       co6_pipeline3;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline3[7:6] <= 0;
        in2_pipeline3[7:6] <= 0;
        sum_pipeline3[5:0] <= 0;
        co6_pipeline3      <= 0;
    end
    else begin 
        in1_pipeline3[7:6] <= in1_pipeline2[7:6];
        in2_pipeline3[7:6] <= in2_pipeline2[7:6];
        sum_pipeline3[5:0] <= {add3[5:4], sum_pipeline2[3:0]};
        co6_pipeline3      <=  add3[6];
    end
end

// 第四级计算：bit6 + bit7
wire [8:6] add4 = in1_pipeline3[7:6] + in2_pipeline3[7:6] + co6_pipeline3;

// 第三级数据寄存
reg [7:0] sum_pipeline4;
reg       co8_pipeline4;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        sum_pipeline4[7:0] <= 0;
        co8_pipeline4      <= 0;
    end
    else begin 
        sum_pipeline4[7:0] <= {add4[7:6], sum_pipeline3[5:0]};
        co8_pipeline4      <=  add4[8];
    end
end

// 输出
assign sum = sum_pipeline4;
assign cout = co8_pipeline4;

endmodule


// 流水线8bit加法器，等效的第二种
module pipeline_add8_2 (
    input   wire            clk     ,
    input   wire            rstn    ,
    input   wire    [7:0]   in1     ,
    input   wire    [7:0]   in2     ,
    input   wire            cin     ,
    output  wire    [7:0]   sum     ,
    output  wire            cout     
);

// 输入数据寄存
reg [7:0] in1_pipeline0, in2_pipeline0;
reg cin_pipeline0;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline0 <= 0;
        in2_pipeline0 <= 0;
        cin_pipeline0 <= 0;
    end
    else begin 
        in1_pipeline0 <= in1;
        in2_pipeline0 <= in2;
        cin_pipeline0 <= cin;
    end
end

// 第一级计算bit1+bit0 & 寄存
reg [7:2] in1_pipeline1, in2_pipeline1;
reg [1:0] sum_pipeline1;
reg       co2_pipeline1;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline1[7:2] <= 0;
        in2_pipeline1[7:2] <= 0;
        sum_pipeline1[1:0] <= 0;
        co2_pipeline1      <= 0;
    end
    else begin 
        in1_pipeline1[7:2] <= in1_pipeline0[7:2];
        in2_pipeline1[7:2] <= in2_pipeline0[7:2];
        // 这里RHS用了拼接符，加法器位宽不由LHS决定，而由表达式自身决定，必须加 3'b0 确保是3bit加法器，有进位输出
        {co2_pipeline1, sum_pipeline1[1:0]} <= { 3'b0 + in1_pipeline0[1:0] + in2_pipeline0[1:0] + cin_pipeline0 };
    end
end

// 第二级计算bit3+bit2 & 寄存
reg [7:4] in1_pipeline2, in2_pipeline2;
reg [3:0] sum_pipeline2;
reg       co4_pipeline2;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline2[7:4] <= 0;
        in2_pipeline2[7:4] <= 0;
        sum_pipeline2[3:0] <= 0;
        co4_pipeline2      <= 0;
    end
    else begin 
        in1_pipeline2[7:4] <= in1_pipeline1[7:4];
        in2_pipeline2[7:4] <= in2_pipeline1[7:4];
        {co4_pipeline2, sum_pipeline2[3:0]} <= { 3'b0 + in1_pipeline1[3:2] + in2_pipeline1[3:2] + co2_pipeline1, sum_pipeline1[1:0] };
    end
end

// 第三级计算bit5+bit4 & 寄存
reg [7:6] in1_pipeline3, in2_pipeline3;
reg [5:0] sum_pipeline3;
reg       co6_pipeline3;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1_pipeline3[7:6] <= 0;
        in2_pipeline3[7:6] <= 0;
        sum_pipeline3[5:0] <= 0;
        co6_pipeline3      <= 0;
    end
    else begin 
        in1_pipeline3[7:6] <= in1_pipeline2[7:6];
        in2_pipeline3[7:6] <= in2_pipeline2[7:6];
        {co6_pipeline3, sum_pipeline3[5:0]} <= { 3'b0 + in1_pipeline2[5:4] + in2_pipeline2[5:4] + co4_pipeline2, sum_pipeline2[3:0] };
    end
end

// 第四级计算bit7+bit6 & 寄存
reg [7:0] sum_pipeline4;
reg       co8_pipeline4;
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        sum_pipeline4[7:0] <= 0;
        co8_pipeline4      <= 0;
    end
    else begin 
        {co8_pipeline4, sum_pipeline4[7:0]} <= { 3'b0 + in1_pipeline3[7:6] + in2_pipeline3[7:6] + co6_pipeline3, sum_pipeline3[5:0] };
    end
end

// 输出
assign sum = sum_pipeline4;
assign cout = co8_pipeline4;
    
endmodule


module tb_pipeline_add8 ();

reg clk;
initial begin 
    clk = 0;
    forever #5 clk = ~clk;
end

reg rstn;
initial begin 
    rstn = 0;
    #10;
    rstn = 1;
end

reg [7:0] in1, in2;
reg cin;
initial begin 
    in1 = 0;
    in2 = 0;
    cin = 0;
    #10;
    forever begin 
        @(posedge clk)
        in1 = $random;
        in2 = $random;
        cin = $random;
    end
end
/*
always @(posedge clk, negedge rstn) begin 
    if(!rstn) begin 
        in1 = 0;
        in2 = 0;
        cin = 0;
    end
    else begin 
        in1 = $random;
        in2 = $random;
        cin = $random;
    end
end
*/

wire [7:0] sum;
wire cout;
pipeline_add8 I0(
    .clk     (clk   )   ,
    .rstn    (rstn  )   ,
    .in1     (in1   )   ,
    .in2     (in2   )   ,
    .cin     (cin   )   ,
    .sum     (sum   )   ,
    .cout    (cout  )    
);

wire [7:0] sum2;
wire cout2;
pipeline_add8_2 I1(
    .clk     (clk   )   ,
    .rstn    (rstn  )   ,
    .in1     (in1   )   ,
    .in2     (in2   )   ,
    .cin     (cin   )   ,
    .sum     (sum2  )   ,
    .cout    (cout2 )    
);

initial begin 
    $dumpfile("pipline.vcd");
    $dumpvars(0, tb_pipeline_add8);
    #500 $finish;
end
    
endmodule